/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package aescfbencryption.encriptacion;

import aescfbencryption.basicOperations.basicOperations;
import aescfbencryption.keys.KeyGen;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Vector;

/**
 *
 * @author JPablo
 */
public class desencriptarCFB {


    Vector textoCifrado;
    String clave;
    String textoOriginal;
    int columnas;

    public void AES(String texto, String palabraClave) throws IOException{
        //Se inicializan los valores
        this.textoCifrado = new Vector();
        this.textoOriginal = "";
        this.clave = palabraClave;
        this.columnas = obtenerNumeroColumnas(clave);//Se obtiene el numero de columnas a partir de la clave


        //Se llena el texto original
        for(int i=0;i<texto.length();i++)
        {
            textoCifrado.add((int)texto.charAt(i));
        }


       int nBloques;
        //Se generan las subMatrices del texto original y se llama a encriptar(matrizTexto) con la matriz generada;
       if((textoCifrado.size()%(4*columnas))==0){
            nBloques = (textoCifrado.size()/(4*columnas));
       }else{
            nBloques = (textoCifrado.size()/(4*columnas))+1;
       }
        borrarArchivo();
        //Se generan las subMatrices del texto original y se llama a encriptar(matrizTexto) con la matriz generada;
        for(int i=0;i<nBloques;i++){
           int[][] matrizTexto = new int[4][columnas];
           for(int j=0; j<4;j++){
                for(int k=0;k<columnas;k++){
                    if((i*16)+(j*4)+k< textoCifrado.size()){
                        //Se llena la matriz a codificar
                        matrizTexto[j][k]= Integer.parseInt(textoCifrado.get((i*16)+(j*4)+k).toString());
                    }else{
                        matrizTexto[j][k]=20;//Se rellena con el caracter escogido
                    }
                }
           }
           encriptar(matrizTexto);
        }
    }

  public void escribirMatriz(int[][] matriz, String operacion) throws IOException{

  try
  {
    BufferedWriter out = new BufferedWriter(new FileWriter("Desencriptacion.txt",true));
    out.write("\n"+operacion);
    for (int i = 0; i < 4; i++){
                out.write("\n");
                for(int j = 0; j<4;j++){
                   out.write(Integer.toHexString( matriz[i][j])+" ");
                }
            }
    out.close();
  }
  catch (IOException e)
 {
 }

  }

   public void borrarArchivo() throws IOException{

  try
  {
    BufferedWriter out = new BufferedWriter(new FileWriter("Desencriptacion.txt",false));
    out.write("Proceso de Desencripacion");

    out.close();
  }
  catch (IOException e)
 {
 }

  }


    public void encriptar(int[][] matrizTexto) throws IOException{

        int[][] matrizAux = matrizTexto;
        matrizTexto = vectoriv;

        //Se obtiene la Clave
        KeyGen key = new KeyGen(clave,columnas);
        key.codKeyWord();
        key.fillKeyMatrix();
        key.getAsciiKeyWord();
        key.getHexKeyWord();
        key.initFillWN();
        key.fillAllWN();
        int[][] llave = key.getW(0);
        int iter=0; // para guardar el numero de iteraciones

        basicOperations operacion = new basicOperations();
        //Primera ronda
        matrizTexto = operacion.AddRoundKey(matrizTexto, llave);
        escribirMatriz(matrizTexto,"\n\n Ronda 0 \n resultado de AddRoundKey:");

        //Ronda intermedia de la 2 a la 10, 12 o 14
       // for(int i=0;i<iter;i++){//Esta funcionando solo para  iteraciones... creo que es porque no se generan mas llaves para los otros casos
        for(int i=0;i<9;i++){
            int ronda = i+1;
            llave = key.getW(i+1); //Se obtiene la clave a utilizar
            matrizTexto = operacion.ByteSub(matrizTexto);
            escribirMatriz(matrizTexto,"\n\nRonda "+ronda+" \n resultado de ByteSub:");
            matrizTexto = operacion.ShiftRow(matrizTexto);
            escribirMatriz(matrizTexto," \n resultado de ShiftRow:");
            matrizTexto = operacion.MixColumns(matrizTexto);
            escribirMatriz(matrizTexto," \n resultado de MixColumns:");
            matrizTexto = operacion.AddRoundKey(matrizTexto, llave);
            escribirMatriz(matrizTexto," \n resultado de AddRoundKey:");
        }

        //Ronda Final
        //llave = key.getW(iter);// se comenta para trabajar solo con  iteraciones
        llave = key.getW(10);
        matrizTexto = operacion.ByteSub(matrizTexto);
        escribirMatriz(matrizTexto,"\n\nRonda 10 \n resultado de ByteSub:");
        matrizTexto = operacion.ShiftRow(matrizTexto);
        escribirMatriz(matrizTexto,"\n resultado de ShiftRow:");
        matrizTexto = operacion.AddRoundKey(matrizTexto, llave);
        escribirMatriz(matrizTexto,"\n resultado de AddRoundKey:");

        matrizTexto = operacion.AddRoundKey(matrizTexto, matrizAux);
        escribirMatriz(matrizTexto,"\n se realiza XOR con el texto plano:");
        // Se añade el resultado al texto codificado



        for(int i=0;i<4;i++){
            for(int j=0;j<columnas;j++){
                textoOriginal = textoOriginal + (char)matrizTexto[i][j];
            }
        }

        vectoriv = matrizAux;

    }





    public int obtenerNumeroColumnas(String clave){
        if(clave.length()<17)
           return 4;
        else{
            if(clave.length()<24)
               return 6;
            else
                return 8;
        }
   }


    public String getClave() {
        return clave;
    }

    public int getColumnas() {
        return columnas;
    }

    public String getTextoOriginal() {
        return textoOriginal;
    }

    public Vector getTextoCifrado() {
        return textoCifrado;
    }

    public void setClave(String clave) {
        this.clave = clave;
    }

    public void setColumnas(int columnas) {
        this.columnas = columnas;
    }

    public void setTextoOriginal(String textoOriginal) {
        this.textoOriginal = textoOriginal;
    }

    public void setTextoCifrado(Vector textoCifrado) {
        this.textoCifrado = textoCifrado;
    }

 int[][] vectoriv = new int[][] {new int[] {2, 3, 1, 1},
                                       new int[] {1, 2, 3, 1},
                                       new int[] {1, 1, 2, 3},
                                       new int[] {3, 1, 1, 2}};
}